﻿/*
 * SpotiFAG - Makes spotify ads less annoying
 * Copyright (C) 2010  ed <tripflag@gmail.com>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License v2
 * (version 2) as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, refer to the following URL:
 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
 */
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Drawing;
using System.Windows.Forms;

namespace spotifag {
    public class Spotify {

        [System.Runtime.InteropServices.DllImport("user32.dll")]
        static extern void SendMessage(IntPtr hwnd, int msg, int wParam, int lParam);
        [System.Runtime.InteropServices.DllImport("user32.dll")]
        static extern bool GetWindowRect(IntPtr hwnd, ref Rectangle rect);
        // I'm ashamed of myself.
        int WM_MOUSEMOVE = 0x200;
        int WM_MOUSEDOWN = 0x201;
        int WM_MOUSEUP = 0x202;

        bool muted;
        Process proc;
        string SPLAT = new string(new char[]{' ', (char)8211, ' '});

        public Spotify() {
            try {
                muted = false;
                proc = Process.GetProcessesByName("spotify")[0];
            } catch { }
        }
        public IntPtr hwnd() {
            return proc.MainWindowHandle;
        }
        public bool lockedOn() {
            return proc != null &&
                !proc.HasExited &&
                proc.MainWindowTitle != null &&
                proc.MainWindowTitle.Length > 0;
        }
        public string track() {
            proc = Process.GetProcessesByName("spotify")[0]; // WHY THE FUCK IS THIS NECESSARY MICROSOFT
            string raw = proc.MainWindowTitle;
            if (raw.Length < 10) return null;
            return raw.Substring(10);
        }

        // Get bottom right coordinate of spotify.exe
        private Point coordBottomRight() {
            Rectangle rect = Rectangle.Empty;
            GetWindowRect(proc.MainWindowHandle, ref rect);
            return (Point)rect.Size;
        }

        // Get coordinates for play/pause button
        private Point coordPlayPause() {
            Point pt = coordBottomRight();
            return new Point(56, pt.Y - 20);
        }

        // Get coordinates for volume slider
        private Point coordVolSlider() {
            Point pt = coordBottomRight();
            return new Point(124, pt.Y - 20);
            // slider region width: 77
        }

        // Will doMute result in a toggle?
        public bool willToggle(bool doMute) {
            return muted != doMute;
        }

        // Mute/unmute
        public bool mute(bool doMute, bool fully) {
            if (muted != doMute) {
                muted = doMute;
                Point pt = coordVolSlider();

                // Old code, just turned down the volume
                //mouse(pt.X + (muted ? 38 : 77), pt.Y);

                // New code, force-resumes with play/pause
                // We need to mute twice, as this handles fullscreen ads
                mouse(pt.X + (muted ? (fully ? 0 : 38) : 77), pt.Y); derp(250);
                mouse(pt.X + (muted ? (fully ? 0 : 38) : 77), pt.Y);
                if (muted && fully) {
                    derp(250);
                    pt = coordPlayPause();
                    mouse(pt.X, pt.Y);
                }
                return true;
            }
            return false;
        }

        // Executes a mouseclick at (x,y)
        private void mouse(int x, int y) {
            IntPtr hwnd = this.hwnd();
            int lparam = y * 0x10000 + x;
            SendMessage(hwnd, WM_MOUSEMOVE, 0, lparam); derp();
            SendMessage(hwnd, WM_MOUSEDOWN, 0, lparam); derp();
            SendMessage(hwnd, WM_MOUSEUP, 0, lparam);
        }

        // Derps a hundred
        void derp() {
            derp(100);
        }

        // Derps durrr
        void derp(int durrr) {
            Application.DoEvents();
            System.Threading.Thread.Sleep(durrr);
        }
    }

    public class S {
        public static string[] split(string a, string b) {
            return a.Split(new string[] { b }, StringSplitOptions.None);
        }
        public static long ms() {
            return DateTime.Now.Ticks / 10000;
        }
    }

    class MP3 {
        int FADEMIN, FADEMAX;
        static int nextID = 1;
        int fadeDir, fadePos;
        string file;
        bool isOpen;
        int id;

        [System.Runtime.InteropServices.DllImport("winmm.dll")]
        static extern long mciSendString(
            string strCommand, StringBuilder strReturn,
            int iReturnLength, IntPtr hwndCallback);

        public MP3(string file, double volume) {
            FADEMAX = (int)Math.Round(1000 * volume);
            FADEMIN = 1;

            System.Windows.Forms.Timer fader = new System.Windows.Forms.Timer();
            fader.Tick += new EventHandler(fader_Tick);
            fader.Interval = 10;
            fader.Start();

            this.file = file;
            fadePos = FADEMAX;
            fadeDir = 0;
            load();
        }

        void load() {
            close();
            id = nextID;
            mci("open \"" + file + "\" type mpegvideo alias " + id);
            isOpen = true;
            nextID++;
        }

        public void close() {
            if (isOpen) {
                mci("close " + id);
                isOpen = false;
            }
        }

        public void play(bool loop) {
            play(loop, FADEMAX);
        }

        public void play(bool loop, int vol) {
            string cmd = "play " + id;
            if (loop) cmd += " REPEAT";
            else cmd += " from 0";

            fadeDir = 0;
            setVol(vol);
            mci(cmd);
        }

        public void play() {
            play(false);
        }

        public void stop() {
            if (isOpen) mci("pause " + id);
        }

        void mci(string str) {
            Console.WriteLine(" -!- MCI: " + str);
            mciSendString(str, null, 0, IntPtr.Zero);
        }

        public void fadeIn() {
            play(true, FADEMIN);
            fadeDir = 1;
        }
        public void fadeOut() {
            fadeDir = -1;
        }
        void fader_Tick(object sender, EventArgs e) {
            if ((fadeDir == 1 && fadePos < FADEMAX) ||
                (fadeDir == -1 && fadePos > FADEMIN)) {
                fadePos += 25 * fadeDir;
                setVol(Math.Min(Math.Max(
                    fadePos, FADEMIN), FADEMAX));
            }
            if (fadePos == FADEMIN &&
                fadeDir != 0)
                stop();
            if (fadePos == FADEMIN ||
                fadePos == FADEMAX)
                fadeDir = 0;
        }
        void setVol(int vol) {
            mci("setaudio " + id + " volume to " + vol);
            fadePos = vol;
        }
        public bool fadeCompleted() {
            return fadeDir == 0;
        }
    }
}
